home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Online / opennap / add_file.c < prev    next >
C/C++ Source or Header  |  2001-06-08  |  14KB  |  619 lines

  1. /* Copyright (C) 2000-1 drscholl@users.sourceforge.net
  2.    This is free software distributed under the terms of the
  3.    GNU Public License.
  4.  
  5.    $Id: add_file.c,v 1.93 2001/02/23 23:38:48 drscholl Exp $ */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <ctype.h>
  11. #include <limits.h>
  12. #include "opennap.h"
  13. #include "debug.h"
  14.  
  15. #ifndef ROUTING_ONLY
  16.  
  17. /* allowed bitrates for MPEG V1/V2 Layer III */
  18. const int BitRate[18] =
  19.     { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192, 224,
  20.     256, 320
  21. };
  22.  
  23. /* allowed sample rates for MPEG V2/3 */
  24. const int SampleRate[6] = { 16000, 24000, 22050, 32000, 44100, 48000 };
  25.  
  26. #if DEBUG
  27. int
  28. validate_flist (FLIST * p)
  29. {
  30.     ASSERT_RETURN_IF_FAIL (VALID_LEN (p, sizeof (FLIST)), 0);
  31.     ASSERT_RETURN_IF_FAIL (p->magic == MAGIC_FLIST, 0);
  32.     ASSERT_RETURN_IF_FAIL (VALID_LEN (p->key, strlen (p->key) + 1), 0);
  33.     ASSERT_RETURN_IF_FAIL (p->count == list_count (p->list), 0);
  34.     return 1;
  35. }
  36. #endif
  37.  
  38. static void
  39. fdb_add (HASH * table, char *key, DATUM * d, int track_key)
  40. {
  41.     FLIST  *files;
  42.     LIST   *list;
  43.  
  44.     ASSERT (table != 0);
  45.     ASSERT (key != 0);
  46.     ASSERT (d != 0);
  47.     files = hash_lookup (table, key);
  48.     /* if there is no entry for this particular word, create one now */
  49.     if (!files)
  50.     {
  51.     files = CALLOC (1, sizeof (FLIST));
  52.     if (!files)
  53.     {
  54.         OUTOFMEMORY ("fdb_add");
  55.         return;
  56.     }
  57. #if DEBUG
  58.     files->magic = MAGIC_FLIST;
  59. #endif
  60.     files->key = STRDUP (key);
  61.     if (!files->key)
  62.     {
  63.         OUTOFMEMORY ("fdb_add");
  64.         FREE (files);
  65.         return;
  66.     }
  67.     if (hash_add (table, files->key, files))
  68.     {
  69.         FREE (files->key);
  70.         FREE (files);
  71.         return;
  72.     }
  73.     }
  74.     ASSERT (validate_flist (files));
  75.  
  76.     list = CALLOC (1, sizeof (LIST));
  77.     if (!list)
  78.     {
  79.     OUTOFMEMORY ("list");
  80.     if (!files->list)
  81.         hash_remove (table, files->key);
  82.     return;
  83.     }
  84.     list->data = d;
  85.     /* order is not important, push to beginning of list for speed */
  86.     files->list = list_push (files->list, list);
  87.     files->count++;
  88.  
  89.     /* this is conditional since we don't keep track of the key when
  90.      * inserting the hash value for the RESUME function.
  91.      */
  92.     if (track_key)
  93.     {
  94.     /* keep a list of search tokens that match this file */
  95.     list = CALLOC (1, sizeof (LIST));
  96.     if (!list)
  97.     {
  98.         /* this is bad.  we've already committed a lot of things, just
  99.          * bail out as best as possible.
  100.          */
  101.         OUTOFMEMORY ("fdb_add");
  102.         return;
  103.     }
  104.     list->data = files;
  105.     d->tokens = list_push (d->tokens, list);
  106.     }
  107. }
  108.  
  109. /* common code for inserting a file into the various hash tables */
  110. static void
  111. insert_datum (DATUM * info, char *av)
  112. {
  113.     LIST   *tokens, *ptr;
  114.     unsigned int fsize;
  115.  
  116.     ASSERT (info != 0);
  117.     ASSERT (av != 0);
  118.  
  119.     if (!info->user->con->uopt->files)
  120.     {
  121.     /* create the hash table */
  122.     info->user->con->uopt->files =
  123.         hash_init (257, (hash_destroy) free_datum);
  124.     if (!info->user->con->uopt->files)
  125.     {
  126.         OUTOFMEMORY ("insert_datum");
  127.         return;
  128.     }
  129.     }
  130.  
  131.     hash_add (info->user->con->uopt->files, info->filename, info);
  132.  
  133.     /* split the filename into words */
  134.     tokens = tokenize (av, NULL);
  135.  
  136.     /* the filename may not consist of any searchable words, in which
  137.      * case its not entered into the index.  this file will only be seen
  138.      * when browsing the user possessing it
  139.      */
  140.     for (ptr = tokens; ptr; ptr = ptr->next)
  141.     fdb_add (File_Table, ptr->data, info, 1);
  142.  
  143.     list_free (tokens, 0);
  144.  
  145. #if RESUME
  146.     /* index by md5 hash */
  147.     fdb_add (MD5, info->hash, info, 0);
  148. #endif
  149.  
  150.     fsize = info->size / 1024;    /* in kbytes */
  151.     info->user->shared++;
  152.     info->user->libsize += fsize;
  153.     Num_Gigs += fsize;        /* this is actually kB, not gB */
  154.     Num_Files++;
  155.     Local_Files++;
  156.     info->user->sharing = 1;    /* note that we began sharing */
  157. }
  158.  
  159. static DATUM *
  160. new_datum (char *filename, char *hash)
  161. {
  162.     DATUM  *info = CALLOC (1, sizeof (DATUM));
  163.  
  164.     (void) hash;
  165.     if (!info)
  166.     {
  167.     OUTOFMEMORY ("new_datum");
  168.     return 0;
  169.     }
  170.     info->filename = STRDUP (filename);
  171.     if (!info->filename)
  172.     {
  173.     OUTOFMEMORY ("new_datum");
  174.     FREE (info);
  175.     return 0;
  176.     }
  177. #if RESUME
  178.     info->hash = STRDUP (hash);
  179.     if (!info->hash)
  180.     {
  181.     OUTOFMEMORY ("new_datum");
  182.     FREE (info->filename);
  183.     FREE (info);
  184.     return 0;
  185.     }
  186. #endif
  187.     return info;
  188. }
  189.  
  190. static int
  191. bitrateToMask (int bitrate, USER * user)
  192. {
  193.     unsigned int i;
  194.  
  195.     for (i = 0; i < sizeof (BitRate) / sizeof (int); i++)
  196.  
  197.     {
  198.     if (bitrate <= BitRate[i])
  199.         return i;
  200.     }
  201.     log ("bitrateToMask(): invalid bit rate %d (%s, \"%s\")", bitrate,
  202.      user->nick, user->clientinfo);
  203.     return 0;            /* invalid bitrate */
  204. }
  205.  
  206. static int
  207. freqToMask (int freq, USER * user)
  208. {
  209.     unsigned int i;
  210.     for (i = 0; i < sizeof (SampleRate) / sizeof (int); i++)
  211.  
  212.     {
  213.     if (freq <= SampleRate[i])
  214.         return i;
  215.     }
  216.     log ("freqToMask(): invalid sample rate %d (%s, \"%s\")", freq,
  217.      user->nick, user->clientinfo);
  218.     return 0;
  219. }
  220.  
  221. /* 100 "<filename>" <md5sum> <size> <bitrate> <frequency> <time>
  222.    client adding file to the shared database */
  223. HANDLER (add_file)
  224. {
  225.     char   *av[6];
  226.     DATUM  *info;
  227.     unsigned int fsize;
  228.  
  229.     (void) tag;
  230.     (void) len;
  231.     ASSERT (validate_connection (con));
  232.  
  233.     CHECK_USER_CLASS ("add_file");
  234.  
  235.     ASSERT (validate_user (con->user));
  236.  
  237.     if (!option(ON_ALLOW_SHARE))
  238.     return;
  239.  
  240.     if (Max_Shared && con->user->shared > Max_Shared)
  241.     {
  242.     send_cmd (con, MSG_SERVER_NOSUCH,
  243.           "You may only share %d files", Max_Shared);
  244.     return;
  245.     }
  246.  
  247.     if (split_line (av, sizeof (av) / sizeof (char *), pkt) != 6)
  248.     {
  249.     unparsable (con);
  250.     return;
  251.     }
  252.  
  253.     if (is_blocked (av[0]))
  254.     return;
  255.  
  256.     if (av[1] - av[0] > _POSIX_PATH_MAX + 2)
  257.     {
  258.     send_cmd (con, MSG_SERVER_NOSUCH, "filename too long");
  259.     return;
  260.     }
  261.  
  262.     /* ensure we have a valid byte count */
  263.     fsize = strtoul (av[2], 0, 10);
  264.     /* check for overflow */
  265.     if (con->user->libsize + fsize < con->user->libsize)
  266.     {
  267.     log ("add_file(): %u byte file would overflow %s's library size",
  268.          fsize, con->user->nick);
  269.     return;
  270.     }
  271.  
  272.     /* make sure this isn't a duplicate - only compare the basename, not
  273.      * including the directory component
  274.      */
  275.     if (con->uopt->files && hash_lookup (con->uopt->files, av[0]))
  276.     {
  277.     send_cmd (con, MSG_SERVER_NOSUCH, "duplicate file");
  278.     return;
  279.     }
  280.  
  281.     /* create the db record for this file */
  282.     if (!(info = new_datum (av[0], av[1])))
  283.     return;
  284.     info->user = con->user;
  285.     info->size = fsize;
  286.     info->bitrate = bitrateToMask (atoi (av[3]), con->user);
  287.     info->frequency = freqToMask (atoi (av[4]), con->user);
  288.     info->duration = atoi (av[5]);
  289.     info->type = CT_MP3;
  290.  
  291.     insert_datum (info, av[0]);
  292. }
  293.  
  294. char   *Content_Types[] = {
  295.     "mp3",            /* not a real type, but what we use for audio/mp3 */
  296.     "audio",
  297.     "video",
  298.     "application",
  299.     "image",
  300.     "text"
  301. };
  302.  
  303. /* 10300 "<filename>" <size> <hash> <content-type> */
  304. HANDLER (share_file)
  305. {
  306.     char   *av[4];
  307.     DATUM  *info;
  308.     int     i, type;
  309.     unsigned int fsize;
  310.  
  311.     (void) len;
  312.     (void) tag;
  313.  
  314.     ASSERT (validate_connection (con));
  315.     CHECK_USER_CLASS ("share_file");
  316.  
  317.     if (!option(ON_ALLOW_SHARE))
  318.     return;
  319.     if (Max_Shared && con->user->shared > Max_Shared)
  320.     {
  321.     log ("add_file(): %s is already sharing %d files", con->user->nick,
  322.          con->user->shared);
  323.     if (ISUSER (con))
  324.         send_cmd (con, MSG_SERVER_NOSUCH,
  325.               "You may only share %d files", Max_Shared);
  326.     return;
  327.     }
  328.  
  329.     if (split_line (av, sizeof (av) / sizeof (char *), pkt) != 4)
  330.     {
  331.     unparsable (con);
  332.     return;
  333.     }
  334.  
  335.     if (is_blocked (av[0]))
  336.     return;
  337.  
  338.     /* make sure the content-type looks correct */
  339.     type = -1;
  340.     for (i = CT_AUDIO; i < CT_UNKNOWN; i++)
  341.     {
  342.     if (!strcasecmp (Content_Types[i], av[3]))
  343.     {
  344.         type = i;
  345.         break;
  346.     }
  347.     }
  348.     if (type == -1)
  349.     {
  350.     log ("share_file(): not a valid type: %s", av[3]);
  351.     if (ISUSER (con) == CLASS_USER)
  352.         send_cmd (con, MSG_SERVER_NOSUCH, "%s is not a valid type",
  353.               av[3]);
  354.     return;
  355.     }
  356.  
  357.     if (av[1] - av[0] > _POSIX_PATH_MAX + 2)
  358.     {
  359.     send_cmd (con, MSG_SERVER_NOSUCH, "filename too long");
  360.     return;
  361.     }
  362.  
  363.     if (con->uopt->files && hash_lookup (con->uopt->files, av[0]))
  364.     {
  365.     send_cmd (con, MSG_SERVER_NOSUCH, "duplicate file");
  366.     return;
  367.     }
  368.  
  369.     fsize = strtoul (av[1], 0, 10);
  370.     if (fsize + con->user->libsize < con->user->libsize)
  371.     {
  372.     log ("share_file(): %u byte file would overflow %s's library size",
  373.          fsize, con->user->nick);
  374.     return;
  375.     }
  376.  
  377.     if (!(info = new_datum (av[0], av[2])))
  378.     return;
  379.     info->user = con->user;
  380.     info->size = fsize;
  381.     info->type = type;
  382.  
  383.     insert_datum (info, av[0]);
  384. }
  385.  
  386. /* 870 "<directory>" "<basename>" <md5> <size> <bitrate> <freq> <duration> [ ... ]
  387.    client command to add multiple files in the same directory */
  388. HANDLER (add_directory)
  389. {
  390.     char   *dir, *basename, *md5, *size, *bitrate, *freq, *duration;
  391.     char    path[_POSIX_PATH_MAX], dirbuf[_POSIX_PATH_MAX];
  392.     int     pathlen, fsize;
  393.     DATUM  *info;
  394.  
  395.     (void) tag;
  396.     (void) len;
  397.     ASSERT (validate_connection (con));
  398.     CHECK_USER_CLASS ("add_directory");
  399.     if (!option(ON_ALLOW_SHARE))
  400.     return;
  401.     dir = next_arg (&pkt);    /* directory */
  402.     if (!dir)
  403.     {
  404.     log ("add_directory(): missing directory component");
  405.     return;
  406.     }
  407.     pathlen = strlen (dir);
  408.     if ((size_t) pathlen >= sizeof (dirbuf) - 1)
  409.     {
  410.     log ("add_directory(): directory component is too long, ignoring");
  411.     return;
  412.     }
  413.     ASSERT ((size_t) pathlen < sizeof (dirbuf) - 1);
  414.     dirbuf[sizeof (dirbuf) - 1] = 0;    /* ensure nul termination */
  415.     strncpy (dirbuf, dir, sizeof (dirbuf) - 1);
  416.  
  417.     if (pathlen > 0 && dirbuf[pathlen - 1] != '\\')
  418.     {
  419.     dirbuf[pathlen++] = '\\';
  420.     dirbuf[pathlen] = 0;
  421.     if ((size_t) pathlen >= sizeof (dirbuf) - 1)
  422.     {
  423.         ASSERT ((size_t) pathlen < sizeof (dirbuf));
  424.         log
  425.         ("add_directory(): directory component is too long, ignoring");
  426.         return;
  427.     }
  428.     }
  429.  
  430.     /* if the client passes a dir + file that is longer than 255 chars,
  431.      * strncpy() won't write a \0 at the end of the string, so ensure that
  432.      * this always happens
  433.      */
  434.     path[sizeof (path) - 1] = 0;
  435.  
  436.     while (pkt)
  437.     {
  438.     if (Max_Shared && con->user->shared > Max_Shared)
  439.     {
  440.         send_cmd (con, MSG_SERVER_NOSUCH,
  441.               "You may only share %d files", Max_Shared);
  442.         return;
  443.     }
  444.     basename = next_arg (&pkt);
  445.     md5 = next_arg (&pkt);
  446.     size = next_arg (&pkt);
  447.     bitrate = next_arg (&pkt);
  448.     freq = next_arg (&pkt);
  449.     duration = next_arg (&pkt);
  450.     if (!basename || !md5 || !size || !bitrate || !freq || !duration)
  451.     {
  452.         unparsable (con);
  453.         return;
  454.     }
  455.  
  456.     strncpy (path, dirbuf, sizeof (path) - 1);
  457.     strncpy (path + pathlen, basename, sizeof (path) - 1 - pathlen);
  458.  
  459.     ASSERT (path[sizeof (path) - 1] == 0);
  460.  
  461.     /* TODO: still seeing crashes here, we must be overwriting the
  462.      * stack on occasion.  quit now if we detect this condition
  463.      */
  464.     if (path[sizeof (path) - 1] != 0)
  465.     {
  466.         log ("add_directory: ERROR! buffer overflow detected");
  467.         return;
  468.     }
  469.  
  470.     if (is_blocked (path))
  471.         continue;
  472.  
  473.     if (con->uopt->files && hash_lookup (con->uopt->files, path))
  474.     {
  475.         send_cmd (con, MSG_SERVER_NOSUCH, "Duplicate file");
  476.         continue;        /* get next file */
  477.     }
  478.  
  479.     fsize = atoi (size);
  480.     if (fsize < 1)
  481.     {
  482.         send_cmd (con, MSG_SERVER_NOSUCH, "invalid size");
  483.         continue;
  484.     }
  485.  
  486.     /* create the db record for this file */
  487.     if (!(info = new_datum (path, md5)))
  488.         return;
  489.     info->user = con->user;
  490.     info->size = fsize;
  491.     info->bitrate = bitrateToMask (atoi (bitrate), con->user);
  492.     info->frequency = freqToMask (atoi (freq), con->user);
  493.     info->duration = atoi (duration);
  494.     info->type = CT_MP3;
  495.  
  496.     insert_datum (info, path);
  497.     }
  498. }
  499.  
  500. #endif /* ! ROUTING_ONLY */
  501.  
  502. /* 10012 <nick> <shared> <size>
  503.    remote server is notifying us that one of its users is sharing files */
  504. HANDLER (user_sharing)
  505. {
  506.     char   *av[3];
  507.     USER   *user;
  508.     int     n;
  509.     double  libsize;
  510.     int     err = 0;
  511.  
  512.     (void) len;
  513.     ASSERT (validate_connection (con));
  514.     CHECK_SERVER_CLASS ("user_sharing");
  515.     if (split_line (av, sizeof (av) / sizeof (char *), pkt) != 3)
  516.     {
  517.     log ("user_sharing: wrong number of arguments");
  518.     return;
  519.     }
  520.     user = hash_lookup (Users, av[0]);
  521.     if (!user)
  522.     {
  523.     log ("user_sharing: no such user %s (from %s)", av[0], con->host);
  524.     return;
  525.     }
  526.  
  527.     do
  528.     {
  529.     n = atoi (av[1]);
  530.     if (n < 0)
  531.     {
  532.         log ("user_sharing: negative file count for user %s", user->nick);
  533.         err = 1;
  534.         break;
  535.     }
  536.     ASSERT (Num_Files >= user->shared);
  537.     Num_Files -= user->shared;
  538.     Num_Files += n;
  539.     user->shared = n;
  540.  
  541.     libsize = strtoul (av[2], 0, 10);
  542.     if (libsize < 0)
  543.     {
  544.         log ("user_sharing: negative library size for user %s",
  545.          user->nick);
  546.         err = 1;
  547.         break;
  548.     }
  549.  
  550.     if (Num_Gigs < user->libsize)
  551.     {
  552.         log
  553.         ("user_sharing: error: Num_Gigs=%f, user->libsize=%u user->nick=%s",
  554.          Num_Gigs, user->libsize, user->nick);
  555.         Num_Gigs = user->libsize;    /* prevent negative count */
  556.         err = 1;
  557.         break;
  558.     }
  559.     Num_Gigs -= user->libsize;
  560.     Num_Gigs += libsize;
  561.     user->libsize = libsize;
  562.     }
  563.     while (0);
  564.  
  565.     if (err)
  566.     {
  567.     /* reset counts */
  568.     Num_Files -= user->shared;
  569.     Num_Gigs -= user->libsize;
  570.     user->shared = 0;
  571.     user->libsize = 0;
  572.     }
  573.  
  574.     pass_message_args (con, tag, "%s %hu %u", user->nick, user->shared,
  575.                user->libsize);
  576. }
  577.  
  578. /* 110 [:sender]
  579.  * unshare all files
  580.  */
  581. HANDLER (unshare_all)
  582. {
  583.     USER   *sender;
  584.     char   *sender_name;
  585.  
  586.     (void) len;
  587.     if (pop_user_server (con, tag, &pkt, &sender_name, &sender))
  588.     return;
  589.     ASSERT (sender != 0);
  590. #ifndef ROUTING_ONLY
  591.     if (ISUSER (con))
  592.     {
  593.     if (!con->uopt->files)
  594.     {
  595.         ASSERT (sender->shared == 0);
  596.         return;    /* nothing shared */
  597.     }
  598.     send_cmd (con, tag, "%d", sender->shared);
  599.     free_hash (con->uopt->files);
  600.     con->uopt->files = 0;
  601.     ASSERT (Local_Files >= sender->shared);
  602.     Local_Files -= sender->shared;
  603.     }
  604. #endif /* !ROUTING_ONLY */
  605.     if (sender->libsize > Num_Gigs)
  606.     {
  607.     log ("unshare_all: sender->libsize=%u Num_Gigs=%f",
  608.         sender->libsize, Num_Gigs);
  609.     Num_Gigs = sender->libsize;
  610.     }
  611.     ASSERT (Num_Gigs >= sender->libsize);
  612.     Num_Gigs -= sender->libsize;
  613.     ASSERT (Num_Files >= sender->shared);
  614.     Num_Files -= sender->shared;
  615.     sender->libsize = 0;
  616.     sender->shared = 0;
  617.     pass_message_args (con, tag, ":%s", sender->nick);
  618. }
  619.